package cn.kinoko.common.utils;

import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;

import java.util.Collection;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 增删改工具
 *
 * @author kinoko
 */
public class CUDHelper<I, R> {

    private CUDHelper() {
    }

    private CUDHelper(Builder<I, R> builder) {
        this.dbIds = builder.dbIds;
        this.reqList = builder.reqList;
        this.idMapper = builder.idMapper;
        this.reqIds = builder.reqList.stream().map(builder.idMapper).collect(Collectors.toList());
    }

    public static <I, R> Builder<I, R> builder() {
        return new Builder<>();
    }

    /**
     * 数据库已有的id
     */
    @NotEmpty
    private Collection<I> dbIds;

    /**
     * 请求的实体列表
     */
    @NotEmpty
    private Collection<R> reqList;

    /**
     * id映射
     */
    @NotNull
    private Function<? super R, I> idMapper;

    /**
     * 请求的id列表
     */
    private Collection<I> reqIds;

    /**
     * 获取新增的实体
     *
     * @return 新增的实体列表
     */
    public List<R> getNewItem() {
        // 从请求中过滤出id为空的，即新增的
        return reqList.parallelStream().filter(r -> idMapper.apply(r) == null).toList();
    }

    /**
     * 获取删除的实体id
     *
     * @return 删除的id集合
     */
    public List<I> getDelItemId() {
        // 从数据库已有的id中，过滤出不在请求的id集合中的id，即为需要删除的id集合
        return dbIds.parallelStream().filter(id -> !reqIds.contains(id)).toList();
    }

    /**
     * 获取更新的实体
     *
     * @return 更新的实体列表
     */
    public List<R> getUpdateItem() {
        // 从请求的id集合中，过滤出数据库已有的id，即为需要更新的
        return reqList.parallelStream().filter(r -> dbIds.contains(idMapper.apply(r))).toList();
    }

    public static class Builder<I, R> {
        private Collection<I> dbIds;
        private Collection<R> reqList;
        private Function<? super R, I> idMapper;

        public Builder<I, R> dbIds(Collection<I> dbIds) {
            this.dbIds = dbIds;
            return this;
        }

        public Builder<I, R> reqList(Collection<R> reqList) {
            this.reqList = reqList;
            return this;
        }

        public Builder<I, R> idMapper(Function<? super R, I> idMapper) {
            this.idMapper = idMapper;
            return this;
        }

        public CUDHelper<I, R> build() {
            return new CUDHelper<>(this);
        }
    }

}
